#include <countermemoryblock.hpp>

//protected:

//    Counter              data[COUNTER_MEMORY_BLOCK_SIZE];
//    CounterMemoryBlock * next;

inline void CounterMemoryBlock::initAllCounterFree()
{
    Counter * ptr(data);
    for(unsigned int n=0 ; n < COUNTER_MEMORY_BLOCK_SIZE ; n++)
        *(ptr++)=0;
}

CounterMemoryBlock::CounterMemoryBlock() : data(), nextFreeCounter(data), next(0)
{
    initAllCounterFree();
}

CounterMemoryBlock::~CounterMemoryBlock()
{
    if( next )
        delete next;
}
/*
CounterMemoryBlock::CounterMemoryBlock(const CounterMemoryBlock &)
{
    throw Exception("CounterMemoryBlock::CounterMemoryBlock(const CounterMemoryBlock &) not allowed!",EXCEPTION_INFOS);
}

CounterMemoryBlock& CounterMemoryBlock::operator=(const CounterMemoryBlock &)
{
    throw Exception("CounterMemoryBlock& CounterMemoryBlock::operator=(const CounterMemoryBlock &) not allowed!",EXCEPTION_INFOS);
    return (*this);
}*/


Counter * CounterMemoryBlock::newCounter()
{
    //at first, check if there any free counter in this block
    if( nextFreeCounter )
    {
        Counter * res(nextFreeCounter++);
        //find the next free Counter in this block
        while( (nextFreeCounter < (data+COUNTER_MEMORY_BLOCK_SIZE)) && (*nextFreeCounter !=0)  )
            nextFreeCounter++;
        //set the nextfreeCounter at null if there is no free counter in this memory block
        if( data+COUNTER_MEMORY_BLOCK_SIZE == nextFreeCounter )
            nextFreeCounter=0;

        //set the counter
        (*res) = 1;

        //return the free counter
        return res;
    }
    else    //if never there is not a free counter in this block, try the next one.
    {
        //if there is no next block of memory, allocate it
        if(!next)
            next = new CounterMemoryBlock();
        //then try to get the next free counter in the next block of memory
        return next->newCounter();
    }
}

void CounterMemoryBlock::delCounter(Counter *adr)
{
    //at first, check if the counter is inside this block of memory
    if( (adr >= data) && (adr < data+COUNTER_MEMORY_BLOCK_SIZE) )
    {
        (*adr) = 0; //free the counter
        if( nextFreeCounter )   //next free counter already set?
        {
            if( nextFreeCounter > adr ) //if the new free counter is better, change it
                nextFreeCounter = adr;
        }
        else                    //no free counter on this block? not the case anymore!
            nextFreeCounter = adr;
    }
    else    //if the adr is not in this block, so check this adr in the next block
    {
        if(!next)
            throw Exception("Fatal Error : This Counter adress does not exist!",EXCEPTION_INFOS);
        next->delCounter(adr);
    }

}
